# Лекция: Singleton Pattern в Java

Singleton - это порождающий шаблон проектирования, который гарантирует, что класс имеет только один экземпляр, и предоставляет глобальную точку доступа к этому экземпляру.

## Пример Singleton класса

```java
public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
```

В этом примере конструктор `Singleton` является приватным, поэтому его нельзя вызвать извне класса. Единственный способ получить экземпляр `Singleton` - это вызвать метод `getInstance`.

## Использование Singleton класса

```java
public class Main {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();

        System.out.println(singleton1 == singleton2); // выводит true
    }
}
```

В этом примере `singleton1` и `singleton2` указывают на один и тот же объект, что подтверждает, что в программе может быть только один экземпляр `Singleton`.

---

# Практические задания

1. **Создайте класс `Singleton` с приватным конструктором и методом `getInstance`.** (Сложность: 1/5)
```java
public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
```

2. **Создайте два экземпляра `Singleton` с помощью метода `getInstance` и проверьте, что они указывают на один и тот же объект.** (Сложность: 1/5)
```java
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();

System.out.println(singleton1 == singleton2); // выводит true
```

3. **Добавьте в класс `Singleton` приватное поле `value` и публичные методы `getValue` и `setValue`. Убедитесь, что значение `value` одинаково для всех экземпляров `Singleton`.** (Сложность: 2/5)
```java
public class Singleton {
    private static Singleton instance;
    private int value;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();

singleton1.setValue(123);

System.out.println(singleton1.getValue()); // выводит 123
System.out.println(singleton2.getValue()); // выводит 123
```

4. **Сделайте класс `Singleton` потокобезопасным.** (Сложность: 3/5)
```java
public class Singleton {
    private static volatile Singleton instance;
    private int value;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}
```

5. **Проверьте потокобезопасность класса `Singleton` с помощью многопоточного кода.** (Сложность: 4/5)
```java
Runnable task = () -> {
    Singleton singleton = Singleton.getInstance();
    singleton.setValue((int) (Math.random() * 100));
    System.out.println(singleton.getValue());
};

Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);

thread1.start();
thread2.start();
```